#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SIZE 1024

std::string GetOtherMessage()
{
    static int cnt = 0; // 第几条信息
    std::string childPid = std::to_string(getpid());
    std::string messageCnt = std::to_string(++cnt);

    std::string message = "pid:";
    message += childPid;
    message += ", message count:";
    message += messageCnt;

    return message; //""+string类型---错误; 隐式类型转换
}
void SubProcessWrite(int wfd)
{
    // 准备信息
    int temp = 1;
    std::string message("Child write to pipe, I am child, ");
    while (true) // 让子进程一直运行, 不停
    {
        std::string info = message + GetOtherMessage();
        // 写
        write(wfd, info.c_str(), info.size());

        sleep(1);
        if (temp == 10) break;
        temp++;
    }
    std::cout << "child quit" << std::endl;
}
void FatherProcessRead(int rfd)
{
    //close(rfd);//直接关闭读端
    char inbuffer[SIZE]; // in表示读 //c99后支持创建动态数组,但不能初始化; Linux上GNU编译器
    while (true)
    {
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer)-1);//-1是为了把最后一个位置留给\0
        if (n > 0) // 字节数
        {
            inbuffer[n] = '\0'; // 数据结尾+ '\0'
            std::cout << inbuffer << std::endl;
        }
        else if (n == 0) // 写端关闭, 读到文件结尾, 返回0;    如果写端未关闭,管道为空,读端会阻塞
        {
            std::cout << "wfd quit, father get return val 0" << std::endl;
            break;
        }
        else // n < 0
        {
            std::cerr << "read fail" << std::endl;
            break;
        }
    }
}
int main()
{
    // 1.创建管道
    int pipefd[2] = {0};  // 0位置是管道读端fd(以读/写方式打开时返回的fd)
    int n = pipe(pipefd); // 专用于打开管道文件的系统调用; 输出型参数
    if (0 != n)
    {
        std::cerr << "pipe create fail" << std::endl; // cerr==C语言中的perrno
    }

    // 2.创建子进程
    pid_t pid = fork();
    if (pid == 0)
    {
        // child
        close(pipefd[0]); // 关闭无用的读端
        // 3.子进程写
        SubProcessWrite(pipefd[1]);
        close(pipefd[1]);

        exit(0);
    }

    // 4.father读
    close(pipefd[1]);
    FatherProcessRead(pipefd[0]);
    close(pipefd[0]);

    // 5.等待回收僵尸子进程
    int status = 0;
    int rid = waitpid(pid, &status, 0);//waitpid(-1, nullptr, 0);//-1表示等待任意子进程, nullptr表示不关心退出状态, 0表示阻塞等待
    if (rid > 0) //等待成功
    {
        // std::cerr << "wait child process done, exit code:" << ((status>>8) & 0xff) << std::endl;
        // std::cerr << "wait child process done, exit sign:" << (status & 0x7f) << std::endl;
        std::cerr << "wait child process done, exit code:" << WEXITSTATUS(status) << std::endl;
        std::cerr << "wait child process done, exit sign:" << WTERMSIG(status) << std::endl;
    }

    return 0;
}